package dk.degofedal.scala.math

class Fraction private (n:Int, d:Int, sn:List[Symbol], sd:List[Symbol]) {
	
	def this(n:Int, d:Int) = this(n, d, List(), List())
	
	private def gcd(x:Int, y:Int):Int = {
		if (x == 0) {
			y
		} else if ( x < 0 ) {
			gcd(-x, y)
		} else if ( y < 0 ) {
			-gcd(x, -y)
		} else {
			gcd(y%x, x)
		}
	}
	
	private def reduce(l1:List[Symbol], l2:List[Symbol]):List[Symbol] = {
		val intersection = l1 intersect l2
		l1.remove(x => l2 contains x)
	}
	
	private val g = gcd(n, d)
	
	val N = n / g
	val D = d / g
	
	val SN = reduce(sn, sd )
	val SD = reduce(sd, sn )
	
	def +(f:Fraction):Fraction = {
		new Fraction((N * f.D + f.N * D), D * f.D )
	}
	
	def -(f:Fraction):Fraction = {
		new Fraction((N * f.D - f.N * D), D * f.D )
	}
	
	def *(f:Fraction):Fraction = {
		new Fraction(N*f.N, D*f.D)
	}
	
	def *(f:Int):Fraction = {
		new Fraction(N*f, D)
	}
	
	def *(s:Symbol):Fraction = {
		new Fraction(N, D, s :: SN, SD)
	}
	
	def /(f:Fraction):Fraction = {
		new Fraction(N*f.D, D*f.N)
	}
	
	def /(f:Int):Fraction = {
		new Fraction(N, D*f)
	}
	
	def /(s:Symbol):Fraction = {
		new Fraction(N, D, SN, s :: SD)
	}

	override def toString() = {
		if( D == 1 ) {
			N.toString
		} else {
			SN foreach(x => print(x))
			N + "/" + D;
		}
	}
}